package com.bell.atensettings.bean;

import com.bell.atensettings.R;

import android.R.integer;
import android.content.Context;
import android.net.NetworkInfo.DetailedState;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.util.Log;

public class AccessPoint implements Comparable
{
    static final String TAG = "Settings.AccessPoint";
    public static final int SECURITY_NONE = 0;
    public static final int SECURITY_WEP = 1;
    public static final int SECURITY_PSK = 2;
    public static final int SECURITY_EAP = 3;
    private static final int STATE_NONE[] = new int[0];
    private static final int STATE_SECURED[] = new int[0];
    private static final String KEY_CONFIG = "key_config";
    private static final String KEY_DETAILEDSTATE = "key_detailedstate";
    private static final String KEY_SCANRESULT = "key_scanresult";
    private static final String KEY_WIFIINFO = "key_wifiinfo";

    enum PskType
    {
        UNKNOWN, WPA, WPA2, WPA_WPA2
    }

    private Context mContext;
    private WifiConfiguration mConfig;
    private WifiInfo mInfo;
    private int mRssi;
    private DetailedState mState;
    private String mSummary;
    boolean wpsAvailable;
    public int security;
    private String bssid;
    ScanResult mScanResult;
    PskType pskType;
    private int networkId;
    public String ssid;

    private static PskType getPskType(ScanResult result)
    {
        boolean wpa = result.capabilities.contains("WPA-PSK");
        boolean wpa2 = result.capabilities.contains("WPA2-PSK");
        if (wpa2 && wpa) {
            return PskType.WPA_WPA2;
        } else if (wpa2) {
            return PskType.WPA2;
        } else if (wpa) {
            return PskType.WPA;
        } else {
            Log.w(TAG, "Received abnormal flag string: " + result.capabilities);
            return PskType.UNKNOWN;
        }
    }

    private static int getSecurity(ScanResult scanresult)
    {
        if (scanresult.capabilities.contains("WEP"))
            return SECURITY_WEP;
        else if (scanresult.capabilities.contains("PSK"))
            return SECURITY_PSK;
        else if (scanresult.capabilities.contains("EAP"))
            return SECURITY_EAP;
        else
            return SECURITY_NONE;
    }

    private void loadConfig(WifiConfiguration wificonfiguration)
    {
        String s;

        if (wificonfiguration.SSID == null)
            s = "";
        else
            s = removeDoubleQuotes(wificonfiguration.SSID);

        ssid = s;
        bssid = wificonfiguration.BSSID;
        security = getSecurity(wificonfiguration);
        networkId = wificonfiguration.networkId;
        mRssi = Integer.MAX_VALUE;
        mConfig = wificonfiguration;
    }

    private void loadResult(ScanResult scanresult)
    {
        ssid = scanresult.SSID;
        bssid = scanresult.BSSID;
        security = getSecurity(scanresult);
        boolean flag;

        if (security != 3 && scanresult.capabilities.contains("WPS"))
            flag = true;
        else
            flag = false;

        wpsAvailable = flag;
        if (security == SECURITY_PSK)
            pskType = getPskType(scanresult);

        networkId = -1;
        mRssi = scanresult.level;
        mScanResult = scanresult;
    }

    private void refresh()
    {
        if (mState != null) {
            setSummary(getStateString(mState));
        } else if (mRssi == Integer.MAX_VALUE) {
            setSummary(mContext.getString(R.string.wifi_not_in_range));
        } else if (mConfig != null && mConfig.status == WifiConfiguration.Status.DISABLED) {
            switch (mConfig.disableReason) {
                case WifiConfiguration.DISABLED_UNKNOWN_REASON: // '\0'
                    setSummary(mContext.getString(R.string.wifi_disabled_generic));
                    break;

                case WifiConfiguration.DISABLED_DNS_FAILURE:
                case WifiConfiguration.DISABLED_DHCP_FAILURE:
                    setSummary(mContext.getString(R.string.wifi_disabled_network_failure));
                    break;

                case WifiConfiguration.DISABLED_AUTH_FAILURE: // '\003'
                    setSummary(mContext.getString(R.string.wifi_disabled_password_failure));
                    break;
            }
        } else {
            StringBuilder summary = new StringBuilder();
            if (mConfig != null)
                summary.append(mContext.getString(R.string.wifi_remembered));
            if (security != 0) {
                if (summary.length() == 0)
                    summary.append(mContext.getString(R.string.wifi_secured_first_item, getSecurityString(true)));
                else
                    summary.append(mContext.getString(R.string.wifi_secured_second_item, getSecurityString(true)));
            }
            if (mConfig == null && wpsAvailable)
                if (summary.length() == 0)
                    summary.append(mContext.getString(R.string.wifi_wps_available_first_item));
                else
                    summary.append(mContext.getString(R.string.wifi_wps_available_second_item));
            setSummary(summary.toString());
        }
    }

    public String getStateString(DetailedState state)
    {
        String[] wifiStatus = mContext.getResources().getStringArray(R.array.wifi_status);

        if (state.ordinal() >= wifiStatus.length)
            return "";

        return wifiStatus[state.ordinal()];
    }

    static int getSecurity(WifiConfiguration config)
    {
        if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
            return SECURITY_PSK;
        }
        if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) || config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
            return SECURITY_EAP;
        }
        return (config.wepKeys[0] != null) ? SECURITY_WEP : SECURITY_NONE;
    }

    public static String convertToQuotedString(String s)
    {
        return (new StringBuilder()).append("\"").append(s).append("\"").toString();
    }

    static String removeDoubleQuotes(String s)
    {
        int i = s.length();

        if (i > 1 && s.charAt(0) == '"' && s.charAt(i - 1) == '"')
            s = s.substring(1, i - 1);
        return s;
    }

    public WifiConfiguration getConfig()
    {
        return mConfig;
    }

    public WifiInfo getInfo()
    {
        return mInfo;
    }

    public DetailedState getState()
    {
        return mState;
    }

    public String getmSummary()
    {
        return mSummary;
    }

    public void setSummary(String summary)
    {
        this.mSummary = summary;
    }

    public int getSecurity()
    {
        return security;
    }

    public void setSecurity(int security)
    {
        this.security = security;
    }

    public int getNetworkId()
    {
        return networkId;
    }

    public void setNetworkId(int networkId)
    {
        this.networkId = networkId;
    }

    public int getmRssi()
    {
        return mRssi;
    }

    public void setmRssi(int mRssi)
    {
        this.mRssi = mRssi;
    }

    public String getBssid()
    {
        return bssid;
    }

    public void setBssid(String bssid)
    {
        this.bssid = bssid;
    }

    public int getLevel()
    {
        if (mRssi == Integer.MAX_VALUE) {
            return -1;
        }
        return WifiManager.calculateSignalLevel(mRssi, 4);
    }

    /**
     * 生成并保存默认的wificonfiguration 相关参数 只能通过未加密的网络类型
     * 
     * @author BELL TAN
     */
    public void generateOpenNetworkConfig()
    {
        if (security != 0)
            throw new IllegalStateException();

        if (mConfig == null) {
            mConfig = new WifiConfiguration();
            mConfig.SSID = convertToQuotedString(ssid);
            mConfig.allowedKeyManagement.set(KeyMgmt.NONE);
        }
    }

    public AccessPoint(Context context, ScanResult scanresult) {
        mContext = context;
        wpsAvailable = false;
        pskType = PskType.UNKNOWN;

        loadResult(scanresult);
        refresh();
    }

    public AccessPoint(Context context, WifiConfiguration wificonfiguration) {
        mContext = context;
        wpsAvailable = false;
        pskType = PskType.UNKNOWN;

        loadConfig(wificonfiguration);
        refresh();
    }

    public int compareTo(Object obj)
    {
        return compareTo((AccessPoint) obj);
    }

    public int compareTo(AccessPoint other)
    {
        //确保活动的接入点在第一位
        if (mInfo != other.mInfo) {
            return (mInfo != null) ? -1 : 1;
        }
        //确保范围内的接入点都在前面
        if ((mRssi ^ other.mRssi) < 0) {
            return (mRssi != Integer.MAX_VALUE) ? -1 : 1;
        }
        //确保已配置的接入点在未配置的前面
        if ((networkId ^ other.networkId) < 0) {
            return (networkId != -1) ? -1 : 1;
        }
        //信号强度重新排序
        int difference = WifiManager.compareSignalLevel(other.mRssi, mRssi);
        if (difference != 0)
            return difference;
        //ssid 重新排序
        return ssid.compareToIgnoreCase(other.ssid);
    }

    public String getSecurityString(boolean flag)
    {
        Context context = mContext;
        switch (security) {
            case SECURITY_EAP:
                return flag ? context.getString(R.string.wifi_security_short_eap) : context
                        .getString(R.string.wifi_security_eap);
            case SECURITY_PSK:
                switch (pskType) {
                    case WPA:
                        return flag ? context.getString(R.string.wifi_security_short_wpa) : context
                                .getString(R.string.wifi_security_wpa);
                    case WPA2:
                        return flag ? context.getString(R.string.wifi_security_short_wpa2) : context
                                .getString(R.string.wifi_security_wpa2);
                    case WPA_WPA2:
                        return flag ? context.getString(R.string.wifi_security_short_wpa_wpa2) : context
                                .getString(R.string.wifi_security_wpa_wpa2);
                    case UNKNOWN:
                    default:
                        return flag ? context.getString(R.string.wifi_security_short_psk_generic) : context
                                .getString(R.string.wifi_security_psk_generic);
                }
            case SECURITY_WEP:
                return flag ? context.getString(R.string.wifi_security_short_wep) : context
                        .getString(R.string.wifi_security_wep);
            case SECURITY_NONE:
            default:
                return flag ? "" : context.getString(R.string.wifi_security_none);
        }
    }

    public void saveWifiState(Bundle savedState)
    {
        savedState.putParcelable(KEY_CONFIG, mConfig);
        savedState.putParcelable(KEY_SCANRESULT, mScanResult);
        savedState.putParcelable(KEY_WIFIINFO, mInfo);

        if (mState != null) {
            savedState.putString(KEY_DETAILEDSTATE, mState.toString());
        }
    }

    public void update(WifiInfo wifiinfo, DetailedState detailedstate)
    {
        if (wifiinfo == null || networkId == -1 || networkId != wifiinfo.getNetworkId()) {
            if (mInfo != null) {
                mInfo = null;
                mState = null;
            }
        } else {
            mRssi = wifiinfo.getRssi();
            mInfo = wifiinfo;
            mState = detailedstate;
        }
        refresh();
    }

    public boolean update(ScanResult scanresult)
    {
        boolean flag;

        if (ssid.equals(scanresult.SSID) && security == getSecurity(scanresult)) {
            if (WifiManager.compareSignalLevel(scanresult.level, mRssi) > 0) {
                mRssi = scanresult.level;
            }
            if (security == 2)
                pskType = getPskType(scanresult);
            flag = true;
            refresh();
        } else {
            flag = false;
        }

        return flag;
    }

}
